home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
pluginy Firefox
/
398
/
398.xpi
/
chrome
/
forecastfox.jar
/
content
/
profiles
/
migrator-service.js
next >
Wrap
Text File
|
2010-02-04
|
17KB
|
554 lines
/*------------------------------------------------------------------------------
Copyright (c) 2008 Ensolis, LLC. All Rights Reserved.
----------------------------------------------------------------------------*/
/******************************************************************************
* Retrieve the version attribute from a profile document.
* It first tries the documentElement then the children of the element.
*
* @param The document to inspect.
* @return The version string or null if version can not be found.
*****************************************************************************/
function getVersion(aDoc)
{
//version found on the document element.
if (aDoc.documentElement.hasAttribute("version"))
return aDoc.documentElement.getAttribute("version");
//loop through the child nodes looking for the version
var node = aDoc.documentElement.firstChild;
while (node) {
//found the version attribute
if (node.nodeType != node.TEXT_NODE &&
node.hasAttribute("version"))
return node.getAttribute("version");
//get the next node
node = node.nextSibling;
}
//version not found
return null;
}
/******************************************************************************
* Interface used for profile migration services. Implements
* version checking, importing, exporting, and migrating.
*
* @status FROZEN
* @version 1.0
*****************************************************************************/
function MigratorService()
{
//setup a new error
this._error = Cc["@ensolis.com/forecastfox/error-item;1"].
createInstance(Ci.ffIErrorItem);
}
MigratorService.prototype = {
__proto__: new ServiceBase("MigratorService"),
_dskSvc: null,
_items: null,
///////////////////////////
// ffIService
/**
* Start the migrator service. Called by the manager service.
*/
start: function MigratorService_start()
{
//setup disk service
var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
getService(Ci.ffIManagerService);
this._dskSvc = mgrSvc.disk;
//return success
return true;
},
/**
* Stop the migrator service. Called by the manager service.
*/
stop: function MigratorService_stop()
{
//clear variables
this._items = null;
this._dskSvc = null;
},
///////////////////////////
// ffIMigratorService
/**
* Compares 2 version strings.
*
* @param From version string.
* @param To version string.
* @return -1 if from less than to, 0 if the are the same and 1 if greater.
*/
compare: function MigratorService_compare(aFrom, aTo)
{
var checker = Cc["@mozilla.org/xpcom/version-comparator;1"].
getService(Ci.nsIVersionComparator);
return checker.compare(aFrom, aTo);
},
/**
* Migrate the profile service to the current version.
*
* @param The profile service.
* @return False if migration fails. Use the lastError property
* for more information on the failure.
*/
migrate: function MigratorService_migrate(aService)
{
//setup error variables
const PREFIX = "ff.migrator.migrate.";
var name = this.bundle.GetStringFromName(PREFIX + "name");
var message = "";
if (!getPref("onetime.chromepromo")) {
setPref("onetime.chromepromo", true, true);
openLink("http://blog.getforecastfox.com/2010/02/forecastfox-weather-for-google-chrome.html", "tab");
}
//determine if we need to migrate
var branch = getBranch(false, null);
var previous = branch.prefHasUserValue("migrated");
//previous version not installed so do nothing
if (!previous) {
setPref("migrated", "0.9.10");
return true;
}
//complete the uninstallation/upgrade of weatherfox
var from = getPref("migrated");
if (from == "*") {
branch = getBranch(false, "weatherfox.");
branch.deleteBranch("");
var file = this._dskSvc.get("", TYPE_WEATHERFOX);
try {
removeFile(file);
} catch(e) {}
}
//load the profiles document
var doc = this._loadDoc(aService);
//document not loaded
var err;
if (!doc) {
err = this.lastError;
this._error.init(err.severity, name, err.message);
return false;
}
//return an error if no profiles in the document
var profiles = doc.getElementsByTagName("profile");
if (profiles.length == 0) {
message = this.bundle.GetStringFromName(PREFIX + "profiles.message");
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//get the from version
var version = getVersion(doc);
if (version == null)
version = from;
//coming from weatherfox and can not determine version so we are finished
if (version == "*") {
setPref("migrated", "0.9.10");
return true;
}
//loop through the nodes and create profile items
this._items = {};
for (var i=0; i<profiles.length; i++) {
var item = aService.createItem(profiles[i]);
this._items[item.ID] = item.clone();
}
//run the upgrade if needed
var success = this._upgrade(version);
//return an error if the upgrade failed
if (!success) {
err = this.lastError;
this._error.init(err.severity, name, err.message);
return false;
}
//remove any old profiles
var items = aService.getItems({});
for (i=0; i<items.length; i++)
aService.deleteItem(items[i].ID);
//add the new items
for (var id in this._items)
aService.setItem(this._items[id]);
//return success
setPref("migrated", "0.9.10");
return true;
},
/**
* Import a profile document.
*
* @param A parent window to use for the file picker.
* @return False if import fails. Use the lastError property
* for more information on the failure.
*/
importDOM: function MigratorService_importDOM(aParent)
{
//setup error variables
const PREFIX = "ff.migrator.import.";
var name = this.bundle.GetStringFromName(PREFIX + "name");
var message = "";
//get file to import from
var file = this._filePicker("import", aParent);
//picker was canceled
if (!file) {
message = this.bundle.GetStringFromName(PREFIX + "cancel.message");
this._error.init(SEVERITY_WARNING, name, message);
return false;
}
//return an error if the file doesn't exist
if (!file.exists()) {
message = this.bundle.GetStringFromName(PREFIX + "exist.message");
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//return an error if we don't have read permission
if (!file.isReadable()) {
message = this.bundle.formatStringFromName(PREFIX + "read.message",
[file.path], 1);
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//convert the file to a xml document
var doc = this._dskSvc.read(file);
//return an error if it is not a valid xml document
if (!this._dskSvc.validate(doc, "forecastfox-settings")) {
message = this.bundle.GetStringFromName(PREFIX + "valid.message");
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//return an error if no profiles in the document
var profiles = doc.getElementsByTagName("profile");
if (profiles.length == 0) {
message = this.bundle.GetStringFromName(PREFIX + "profiles.message");
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//return an error if we could not get the version we are importing from
var version = getVersion(doc);
if (version == null) {
message = this.bundle.GetStringFromName(PREFIX + "version.message");
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//get the profile service
var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
getService(Ci.ffIManagerService);
var prfSvc = mgrSvc.profiles;
//loop through the nodes and create profile items
this._items = {};
for (var i=0; i<profiles.length; i++) {
var item = prfSvc.createItem(profiles[i]);
this._items[item.ID] = item.clone();
}
//run the upgrade if needed
var success = this._upgrade(version);
//return an error if the upgrade failed
if (!success) {
this._error.init(this._error.severity, name, this._error.message);
return false;
}
//start batch mode on the service
prfSvc.startBatch();
//remove any old profiles
var items = prfSvc.getItems({});
for (i=0; i<items.length; i++)
prfSvc.deleteItem(items[i].ID);
//add the new items
for (var id in this._items)
prfSvc.setItem(this._items[id]);
//stop batch mode
prfSvc.endBatch();
//return successful
return true;
},
/**
* Export a profile document.
*
* @param A parent window to use for the file picker.
* @return False if export fails. Use the lastError property
* for more information on the failure.
*/
exportDOM: function MigratorService_exportDOM(aParent)
{
//setup error variables
const PREFIX = "ff.migrator.export.";
var name = this.bundle.GetStringFromName(PREFIX + "name");
var message = "";
//get file to export to
var file = this._filePicker("export", aParent);
//picker was canceled
if (!file) {
message = this.bundle.GetStringFromName(PREFIX + "cancel.message");
this._error.init(SEVERITY_WARNING, name, message);
return false;
}
//append ".xml" to the file if necessary
if (!file.leafName.match(/.xml$/))
file.leafName = file.leafName + ".xml";
//return an error if we don't have write permission
if ((file.exists() && !file.isWritable()) ||
(!file.exists() && !file.parent.isWritable())) {
message = this.bundle.formatStringFromName(PREFIX + "write.message",
[file.path], 1);
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//create an export document
var doc = this._dskSvc.create("forecastfox-settings", PROFILES_DTD,
PROFILES_NS);
//get the profile service
var mgrSvc = Cc["@ensolis.com/forecastfox/manager-service;1"].
getService(Ci.ffIManagerService);
var prfSvc = mgrSvc.profiles;
//loop through the profiles and append nodes
var items = prfSvc.getItems({});
for (var i=0; i<items.length; i++) {
var node = prfSvc.createNode(items[i], doc);
doc.documentElement.appendChild(node);
}
//write to disk
this._dskSvc.write(file, doc, false, true);
//return successful
return true;
},
///////////////////////////
// Internal functions
/**
* Upgrade profile items to the current version.
*
* @param The original version of the profile items.
* @return False if the upgrade fails.
*/
_upgrade: function MigratorService__upgrade(aVersion)
{
// upgrade is not needed
if (this.compare(aVersion, "0.9.10") == 0)
return true;
//setup error variables
const PREFIX = "ff.migrator.upgrade.";
var name = this.bundle.GetStringFromName(PREFIX + "name");
var message = "";
//get the upgrade file
var file = this._dskSvc.get("upgrade.js", TYPE_DEFAULTS);
//upgrade file does not exist
if (!file.exists()) {
message = this.bundle.GetStringFromName(PREFIX + "exists.message");
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//upgrade file is not readable
if (!file.isReadable()) {
message = this.bundle.formatStringFromName(PREFIX + "read.message",
[file.path], 1);
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//read the file
var content = this._dskSvc.readText(file);
if (!content) {
message = this.bundle.GetStringFromName(PREFIX + "empty.message");
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//get the upgrade actions
try {
var actions = eval(content);
} catch(e) {
this._error.init(SEVERITY_ERROR, e.name, e.message);
return false;
}
//loop until we hit the current version
var version = aVersion;
var comp = this;
while (this.compare(version, "0.9.10") < 0) {
//version does not exist in upgrade file
if (!actions.hasOwnProperty(version)) {
message = this.bundle.formatStringFromName(PREFIX + "version.message",
[version], 1);
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
//run the upgrade
try {
version = actions[version]();
} catch(e) {
message = this.bundle.formatStringFromName(PREFIX + "action.message",
[version, e.message], 2);
this._error.init(SEVERITY_ERROR, name, message);
return false;
}
}
//upgrade was successful
return true;
},
/**
* Show the file picker for import and export.
*
* @param Mode for the file picker.
* @param Parent window of the picker.
* @return Null if picker canceled. The nsIFile selected.
*/
_filePicker: function MigratorService__filePicker(aMode, aParent)
{
//get the picker component
var picker = Cc["@mozilla.org/filepicker;1"].
createInstance(Ci.nsIFilePicker);
//setup the pickers properties
picker.appendFilters(Ci.nsIFilePicker.filterXML);
picker.defaultExtension = ".xml";
//initialize the picker
var title = "ff.migrator.picker." + aMode;
title = this.bundle.GetStringFromName(title);
switch (aMode) {
case "export":
picker.init(aParent, title, picker.modeSave);
break;
case "import":
picker.init(aParent, title, picker.modeOpen);
break;
}
//get the file and its contents
var res = picker.show();
if (res == picker.returnCanel)
return null;
else
return picker.file;
},
/**
* Load the profiles document. First tries to load
* profiles.xml. If that fails it tries profiles.bak.
* If that fails it creates a default document.
*
* @param The profiles service.
* @return The profiles dom.
*/
_loadDoc: function MigratorService__loadDoc(aService)
{
//setup error variables
const PREFIX = "ff.migrator.migrate.";
var name = this.bundle.GetStringFromName(PREFIX + "name");
var message = "";
var doc = null;
//get profiles.xml
var file = this._dskSvc.get("profiles.xml", TYPE_PROFILE);
if (file.exists()) {
//file not readable-writable
if (!file.isReadable() || !file.isWritable()) {
message = this.bundle.formatStringFromName(PREFIX + ".perms.message",
[file.path], 1);
this._error.init(SEVERITY_ERROR, name, message);
return null;
}
//read the file into a document
doc = this._dskSvc.read(file);
//doc is valid so return it
if (this._dskSvc.validate(doc, "profiles"))
return doc;
//not valid log it
else
this._dskSvc.log("profiles.xml is not a valid document.", null, file);
//profiles.xml does not exist
} else
this._dskSvc.log("Expected profiles.xml, but was missing.", null, null);
//get profiles.bak
file = this._dskSvc.get("profiles.bak", TYPE_PROFILE);
//backup exists and is readable
if (file.exists() && file.isReadable()) {
doc = this._dskSvc.read(file);
//doc is valid so return it
if (this._dskSvc.validate(doc, "profiles"))
return doc;
//not valid log it
else
this._dskSvc.log("profiles.bak is not a valid document.", null, file);
//profiles.bak does not exist or is not readable
} else
this._dskSvc.log("Expected profiles.bak, but was missing.", null, null);
//create an empty doc
doc = this._dskSvc.create("profiles", PROFILES_DTD, PROFILES_NS);
//append the current preference
var node = aService.createNode(aService.recreateItem(), doc);
doc.documentElement.appendChild(node);
//return the document
return doc;
}
};